﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Ast.Core.Services;
using Ast.Core.Settings;
using Ast.Framework.Forms;
using Ast.Framework.Logging;
using Autofac.Features.Metadata;
using Castle.Components.DictionaryAdapter;
using Castle.Core.Logging;
using NLog;
using NLog.Config;

namespace Ast
{
    [FormMetadata(FormType.Main)]
    public partial class MainForm : Form
    {
        private readonly IDeviceProvider _deviceProvider;
        private readonly IFormFactory _formFactory;
        private readonly ILogSettings _logSettings;
        private readonly ISymbolService _symbolService;
        private readonly IEnumerable<Meta<Lazy<Form>>> _formMetadatas;
        private readonly IDictionaryAdapterFactory _dictionaryAdapterFactory;
        private readonly ILoggingMessageQueue _loggingMessageQueue;

        private FastRichTextBoxTarget _logTarget;

        public MainForm(IFormFactory formFactory,
            IDeviceProvider deviceProvider,
            ILogSettings logSettings,
            ISymbolService symbolService,
            IEnumerable<Meta<Lazy<Form>>> formMetadatas,
            IDictionaryAdapterFactory dictionaryAdapterFactory,
            ILoggingMessageQueue loggingMessageQueue)
        {
            _formFactory = formFactory;
            _deviceProvider = deviceProvider;
            _logSettings = logSettings;
            _symbolService = symbolService;
            _formMetadatas = formMetadatas;
            _dictionaryAdapterFactory = dictionaryAdapterFactory;
            _loggingMessageQueue = loggingMessageQueue;

            Logger = NullLogger.Instance;

            InitializeComponent();
        }

        public ILogger Logger { get; set; }

        private async void MainForm_Load(object sender, EventArgs e)
        {
            await Task.Run(() => AttachLogger()).ConfigureAwait(false);
            await Task.WhenAll(Task.Run(() => _deviceProvider.InstallDriver()), Task.Run(() => _symbolService.Initialize())).ConfigureAwait(false);
            await Task.Run(() => AddTabs()).ConfigureAwait(false);
        }

        private void AddTabs()
        {
            var tabPages = _formMetadatas.Select(x => _dictionaryAdapterFactory.GetAdapter<IFormMetadata>(x.Metadata as IDictionary))
                .Where(x => x.IsTabForm)
                .OrderBy(x => x.Order)
                .Select(x => new FormTabPage(x.Type, _formFactory) as TabPage)
                .ToArray();
            if (tabPages.Length == 0) return;

            tabControl.Invoke(new Action(() =>
            {
                tabControl.TabPages.AddRange(tabPages);
                tabPages.First().Select();
            }));
        }

        private void AttachLogger()
        {
            // add textbox log target and rule
            _logTarget = new FastRichTextBoxTarget(_loggingMessageQueue) {Name = "txbLogTarget", FormName = Name, ControlName = logBox.Name, AutoScroll = _logSettings.AutoScroll, MaxLines = _logSettings.MaxLines, Layout = _logSettings.Layout, UseDefaultRowColoringRules = _logSettings.UseDefaultRowColoringRules};
            var logRule = new LoggingRule("*", LogLevel.Info, _logTarget); // info+

            // set nlog config
            var config = LogManager.Configuration;
            config.AddTarget("textbox", _logTarget);
            config.LoggingRules.Add(logRule);
            LogManager.Configuration = config; // have to assign back to activate new rule and target

            // autoscroll
            ckbAutoscroll.Invoke(new Action(() => ckbAutoscroll.Checked = _logSettings.AutoScroll));
            ckbAutoscroll.CheckedChanged += (sender, args) => { _logTarget.AutoScroll = ckbAutoscroll.Checked; };
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            _logTarget.CleanLogs();
        }
    }
}